#include "mmap_file.h"
#include "common.h"

static int debug = 1;

namespace tfs{
    namespace largefile{
        MMapFile::MMapFile():file_size_( 0 ),fd_(-1),data_(nullptr){

        }

        MMapFile::MMapFile(int fd):file_size_( 0 ),fd_(-1),data_(nullptr){

        }

        MMapFile::MMapFile(int fd , const struct MMapOption &option ):
            file_size_( 0 ),fd_( fd ),data_(nullptr){
            mmap_file_option_.max_mmap_size_ = option.max_mmap_size_;
            mmap_file_option_.first_mmap_size_ =option.first_mmap_size_;
            mmap_file_option_.per_mmap_size_ = option.per_mmap_size_;
        }

        MMapFile::~MMapFile(){
            if( data_ ) {
                if( debug ) {
                    std::cout<<"mmap file destroy.."<<"fd: "<<fd_<<" size: "<<file_size_
                            <<", data:"<<data_ <<std::endl;
                }
            // 对文件进行同步
            msync( data_ , file_size_ , MS_SYNC );
            munmap_file(); 
           }
           data_ = nullptr;
           file_size_ = 0;
           fd_ = -1;
           memset( &mmap_file_option_ , 0 , sizeof(mmap_file_option_));
        }

        // 将文件映射到内存
        bool MMapFile::mmap_file( const bool wirte ){
            if( fd_ < 0 )   return false;
            if( mmap_file_option_.max_mmap_size_ == 0 )   return false;

            if( file_size_ < mmap_file_option_.max_mmap_size_ ){
                file_size_ = mmap_file_option_.first_mmap_size_;
            }else{
                file_size_ = mmap_file_option_.max_mmap_size_;
            }
            
            int flags = PROT_READ ;
            if( wirte ){
                flags |= PROT_WRITE ;
            }
            if( !ensure_file_size( file_size_ ) ){
                std::cerr<<"mmap_file-->ensure_file_size  error. desc error:"<<strerror(errno)<<" file size:"<<file_size_<<std::endl;
                return false;
            }
            data_ =  mmap( nullptr ,file_size_ , flags ,MAP_SHARED , fd_, 0 );
            if( data_ == MAP_FAILED ){
                std::cerr<<"mmap file failed . "<<strerror( errno )<<std::endl;;
                data_ = nullptr;
                fd_  = -1;
                file_size_ = 0 ;
                return false;
            }
            if( debug ){
                std::cout<<"mmap file successed  fd:"<<fd_
                        <<", file size: "<<file_size_
                        <<", data addr: "<<data_<<std::endl;
            }
            return true;
        }

        // 映射同步文件
        bool MMapFile::sync_file( ){
            if( data_ && file_size_ > 0){
                return  msync( data_ ,file_size_ , MS_ASYNC ) == 0 ;
        }
            return true;
        }

        void *MMapFile::get_data( )const{
            return data_;
        }

        // 获取数据大小
        int32_t MMapFile::get_size()const{
            return file_size_;
        }

        bool MMapFile::munmap_file( ){
            if( !data_ ){
                return true;
            }
            return munmap( data_ ,file_size_ ) ==0 ;
        }

        bool MMapFile::ensure_file_size( const int32_t size ){
            struct stat fileStat;

            if ( fstat( fd_ ,&fileStat ) == -1){
                std::cerr<<"fstat error. error desc: "<<strerror(errno)<<std::endl;
                return false;
            }
            if( fileStat.st_size < size ){
                if( ftruncate( fd_ , size ) == -1){
                    std::cerr<<"ftruncate error. error desc: "<<strerror(errno)<<std::endl;
                    return false;
                }
            }
            return true;
        }


        bool MMapFile::remap_file(){
            if( fd_ == -1 || data_ == nullptr ){
                std::cerr<<"have not mmap"<<std::endl;
                return false;
            }
            if( file_size_  == mmap_file_option_.max_mmap_size_ ){
                std::cerr<<"is Reach max mmap size."<<std::endl;
                return false;
            }
            // 新的大小
            int32_t new_size = file_size_ + mmap_file_option_.per_mmap_size_;
            if( new_size > mmap_file_option_.max_mmap_size_ ){
                new_size = mmap_file_option_.max_mmap_size_;
            }
            // 同步扩容文件大小
            if( !ensure_file_size( new_size )){
                std::cerr<<"remap_file-->ensure_file_size  error. desc error:"<<strerror(errno)<<" file size:"<<file_size_<<std::endl;
                return false;
            }
            if(debug){
                std::cout<<"fd :"<<fd_
                        <<", start file size :"<< file_size_<<"  new file size: "<<new_size<<std::endl;
            }
            // 重新映射
            void *new_data = mremap( data_ ,file_size_ ,new_size ,MREMAP_MAYMOVE );
            if( new_data == (void *)-1){
                std::cerr<<"mremap error . error desc:"<<strerror(errno)<<" new size:"<<new_size
                         <<", fd :"<<fd_<<", new data:"<<new_data<<", old data"<<data_<<std::endl;
                return false;
            }
            file_size_ = new_size;
            data_ = new_data;
            return true;
        }   
    }
}